package JasPerl::PSGI::Request;

use strict;
use warnings;

use parent qw(JasPerl::Request);

use JasPerl::Util::Attributes;
use JasPerl::Util::Enumeration;
use JasPerl::Util::Locale;
use JasPerl::Util::Cookie;

use Socket; # for inet_ntoa

use Plack::Request;

use JasPerl::PSGI::Response;

sub new {
    my ($class, $env) = @_;
    my $self = bless {
        env => $env,
        request => Plack::Request->new($env),
        attributes => JasPerl::Util::Attributes->new()
    }, $class;
    return $self;
}

sub new_response {
    my $self = shift;
    return JasPerl::PSGI::Response->new(@_);
}

sub get_attribute {
    return shift->{attributes}->get_attribute(@_);
}

sub get_attribute_names {
    return shift->{attributes}->get_attribute_names();
}

sub get_character_encoding {
    return scalar $_[0]->{request}->headers->content_type_charset();
}

sub get_content_length {
    my $content_length = $_[0]->{env}->{CONTENT_LENGTH};
    return defined $content_length ? $content_length : -1;
}

sub get_content_type {
    return $_[0]->{env}->{CONTENT_TYPE};
}

sub get_local_addr {
    return inet_ntoa(scalar gethostbyname($_[0]->{env}->{SERVER_NAME}));
}

sub get_local_name {
    return $_[0]->{env}->{SERVER_NAME};
}

sub get_local_port {
    return $_[0]->{env}->{SERVER_PORT};
}

sub get_locale {
    # cache result from parent class
    return $_[0]->{locale} ||= $_[0]->SUPER::get_locale();
}

sub get_parameter_map {
    # cache multi-value parameters as hash of arrays
    return $_[0]->{parameters} ||= $_[0]->{request}->parameters->multi;
}

sub get_protocol {
    return $_[0]->{env}->{SERVER_PROTOCOL};
}

sub get_reader {
    return $_[0]->{request}->input;
}

sub get_remote_addr {
    return $_[0]->{env}->{REMOTE_ADDR};
}

sub get_remote_host {
    return $_[0]->{env}->{REMOTE_HOST} || $_[0]->{env}->{REMOTE_ADDR};
}

sub get_remote_port {
    return $_[0]->{env}->{REMOTE_PORT};
}

sub get_scheme {
    return $_[0]->{request}->scheme;
}

sub is_secure {
    return $_[0]->{request}->secure;
}

sub remove_attribute {
    return shift->{attributes}->remove_attribute(@_);
}

sub set_attribute {
    return shift->{attributes}->set_attribute(@_);
}

sub set_character_encoding {
    # FIXME: set parameter encoding?
}

# HTTP::Request interface

sub get_auth_type {
    # FIXME: Plack::Middleware::Auth::Basic doesn't set AUTH_TYPE
}

sub get_cookies {
    # FIXME
    my $cookies = $_[0]->{request}->cookies;
    my @cookies = map { JasPerl::Util::Cookie->new($_, $cookies->{$_}) } keys %{$cookies};
    return \@cookies;
}

sub get_header {
    # PSGI always has single (combined) header
    return scalar $_[0]->{request}->header($_[1]);
}

sub get_header_names {
    return JasPerl::Util::Enumeration->from_list(
        $_[0]->{request}->headers->header_field_names
    );
}

sub get_headers {
    return JasPerl::Util::Enumeration->from_list(
        $_[0]->{request}->header($_[1])
    );
}

sub get_method {
    return $_[0]->{env}->{REQUEST_METHOD};
}

sub get_path_info {
    return $_[0]->{env}->{PATH_INFO};
}

sub get_path_translated {
    # FIXME: no path translated in PSGI?
    return $_[0]->{env}->{PATH_TRANSLATED};
}

sub get_query_string {
    # QUERY_STRING must be present if empty
    my $query_string = $_[0]->{env}->{QUERY_STRING};
    return unless length $query_string;
    return $query_string;
}

sub get_remote_user {
    return $_[0]->{env}->{REMOTE_USER};
}

sub get_script_name {
    # SCRIPT_NAME must be present if empty
    return $_[0]->{env}->{SCRIPT_NAME};
}

sub get_session {
    # FIXME
}

# TODO: various isRequestedSessionId... methods

1;
